﻿// <copyright file="FormsUtility.cs" company="City of Portland, BES-ASM">
// </copyright>
// <summary>FormsUtility class</summary>

namespace BESASM.EMGAATS.UI.ArcMap
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  using BESASM.EMGAATS.BusinessClasses;
  using ESRI.ArcGIS.Carto;
  using ESRI.ArcGIS.esriSystem;
  using FluentValidation.Results;

  /// <summary>
  /// A utility class for working with Windows Forms within ArcMap
  /// </summary>
  public static class FormsUtility
  {
    private static ApplicationWindow applicationWindow;

    /// <summary>
    /// Gets a wrapper for the ArcMap application window for use as owner for other Forms
    /// </summary>
    public static IWin32Window ApplicationWindow
    {
      get
      {
        if (applicationWindow == null)
        {
          applicationWindow = new ApplicationWindow(ArcMap.Application.hWnd);
        }

        return applicationWindow;
      }
    }

    /// <summary>
    /// Safely executes an action by catching and displaying any exception to the user.
    /// </summary>
    /// <param name="action">The action to perform.</param>
    /// <param name="sourceWindow">The source window to be used as owner for displaying any error messages. Defaults to the ArcMap application window when null.</param>
    public static void SafeExecute(Action action, IWin32Window sourceWindow = null)
    {
      try
      {
        action();
      }
      catch (Exception ex)
      {
        ShowError(ex, sourceWindow);
      }
    }

    /// <summary>
    /// Shows a message to the user.
    /// </summary>
    /// <param name="message">The message to show.</param>
    /// <param name="owner">The owning window to display the message in front of. Defaults to the ArcMap application window when null.</param>
    public static void ShowMessage(string message, IWin32Window owner = null)
    {
      MessageBox.Show(owner == null ? ApplicationWindow : owner, message, "EMGAATS", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }

    /// <summary>
    /// Shows a warning to the user.
    /// </summary>
    /// <param name="warning">The warning message to show.</param>
    /// <param name="owner">The owning window to display the warning in front of. Defaults to the ArcMap application window when null.</param>
    public static void ShowWarning(string warning, IWin32Window owner = null)
    {
      MessageBox.Show(owner == null ? ApplicationWindow : owner, warning, "EMGAATS", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }

    /// <summary>
    /// Shows an error message to the user.
    /// </summary>
    /// <param name="error">The error message to show.</param>
    /// <param name="owner">The owning window to display the error in front of. Defaults to the ArcMap application window when null.</param>
    public static void ShowError(string error, IWin32Window owner = null)
    {
      MessageBox.Show(owner == null ? ApplicationWindow : owner, error, "EMGAATS", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    /// <summary>
    /// Shows an error message to the user.
    /// </summary>
    /// <param name="ex">The exception that contains the error message.</param>
    /// <param name="owner">The owning window to display the error in front of. Defaults to the ArcMap application window when null.</param>
    public static void ShowError(Exception ex, IWin32Window owner = null)
    {
      string msg = ex.GetType().FullName + ": " + ex.Message;
      msg += Environment.NewLine + ex.StackTrace;
      ShowError(msg, owner);
    }

    /// <summary>
    /// Shows the validation report form for the given validation results.
    /// </summary>
    /// <param name="validation">The validation results to report.</param>
    public static void ShowValidation(ValidationResult validation)
    {
      ValidationReportForm validationForm = new ValidationReportForm(validation);
      validationForm.SelectionChanged += ValidationForm_SelectionChanged;
      validationForm.Show(ApplicationWindow);
    }

    private static void ValidationForm_SelectionChanged(object sender, EventArgs e)
    {
      if (EmgaatsExtension.Instance == null || EmgaatsExtension.Instance.NetworkManager == null || !EmgaatsExtension.Instance.NetworkManager.IsLoaded)
      {
        return;
      }

      ValidationReportForm reportForm = sender as ValidationReportForm;
      if (reportForm != null && reportForm.Visible)
      {
        IMap map = ArcMap.Document.FocusMap;
        map.ClearSelection();

        Dictionary<EntityType, IFeatureSelection> entityLayers = new Dictionary<EntityType, IFeatureSelection>();
        Dictionary<EntityType, List<int>> selectedOids = new Dictionary<EntityType, List<int>>();

        foreach (var failure in reportForm.SelectedFailures)
        {
          IEntity entity = failure.SourceObject() as IEntity;
          if (entity != null)
          {
            int oid = EmgaatsExtension.Instance.NetworkManager.GetObjectIdForEntity(entity);
            if (oid != 0)
            {
              if (!selectedOids.ContainsKey(entity.EntityType))
              {
                selectedOids[entity.EntityType] = new List<int>();
              }

              selectedOids[entity.EntityType].Add(oid);

              if (!entityLayers.ContainsKey(entity.EntityType))
              {
                entityLayers[entity.EntityType] = FeatureLayerUtility.GetEntityLayer(map, entity.EntityType) as IFeatureSelection;
              }
            }
          }
        }

        IActiveView activeView = ArcMap.Document.ActiveView;
        activeView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, activeView.Extent);

        HashSet<IFeatureSelection> selectionLayers = new HashSet<IFeatureSelection>();
        foreach (EntityType entityType in entityLayers.Keys)
        {
          IFeatureSelection layerSelection = entityLayers[entityType];
          int[] oids = selectedOids[entityType].ToArray();
          layerSelection.SelectionSet.AddList(oids.Length, ref oids[0]);

          selectionLayers.Add(layerSelection);
        }

        foreach (IFeatureSelection featureSelection in selectionLayers)
        {
          featureSelection.SelectionChanged();
        }

        activeView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, activeView.Extent);

        if (reportForm.ZoomToSelected)
        {
          UID uid = new UIDClass();
          uid.Value = "esriArcMapUI.ZoomToSelectedCommand";
          uid.SubType = 3;
          var zoomCommand = ArcMap.Application.Document.CommandBars.Find(uid);
          zoomCommand.Execute();
        }
      }
    }
  }
}
